/**   
 * @Title: ShiroConfig.java
 * @Package com.nbst.config
 * @Description:
 * @author King  
 * @date 2018-8-29  
 */

package com.nbst.config.shiro;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

import javax.servlet.Filter;

import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import com.nbst.shiro.MyRealm;

/**
 * @ClassName: ShiroConfig
 * @Description:shiro配置类
 * @author King
 * @date 2018-8-29
 * 
 */
@Configuration
public class ShiroConfig {
	private Logger logout = LoggerFactory.getLogger(ShiroConfig.class);

	/**
	 * 创建ShiroFilterFactoryBaen shiro过滤器
	 */
	@Bean
	public ShiroFilterFactoryBean getShiroFilterFactoryBaen() {
		logout.info("正在加载shiro过滤器...");
		ShiroFilterFactoryBean shiroFilterFactoryBaen = new ShiroFilterFactoryBean();
		// 设置安全管理器
		shiroFilterFactoryBaen.setSecurityManager(getDefaultWebSecurityManager());

		Map<String, Filter> filters = new HashMap<String, Filter>();
		// 添加shiro内置过滤器
		/**
		 * shiro内置过滤器，可以实现权限相关的拦截器
		 * 
		 * 常用的过滤器： anon:无需认证(登录)就可以访问 authc:必须认证才可以访问 user:如果使用rememberMe的功能可以直接访问
		 * perms:该资源必须得到资源权限才可以访问 role:该资源必须得到角色权限才可以访问
		 */

		Map<String, String> filrerMap = new LinkedHashMap<String, String>();
		// 相同路径下的资源 anon等级的一定要在authc前面

		// 放行的资源
		// filrerMap.put("/", "anon");
		filrerMap.put("/login.action", "anon");
		filrerMap.put("/open/api/mes.action", "anon");
		filrerMap.put("/bill/**", "anon");
		filrerMap.put("/fonts/**", "anon");
		filrerMap.put("/app/**", "anon");
		filrerMap.put("/images/**", "anon");
		filrerMap.put("/js/**", "anon");
		filrerMap.put("/css/**", "anon");
		filrerMap.put("/plugins/**", "anon");
		// filrerMap.put("/in", "authc");
		filrerMap.put("/getSession.action", "authc");

		shiroFilterFactoryBaen.setFilters(filters);

		// 修改调整的登录页面
		shiroFilterFactoryBaen.setLoginUrl("/");
		// 配置登录成功的页面
		// shiroFilterFactoryBaen.setSuccessUrl("/index_sy");
		// 设置未授权提示页面
		shiroFilterFactoryBaen.setUnauthorizedUrl("/noAuth");

		// 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
		filrerMap.put("/logout", "logout");

		// 授权过滤器,必须授权才可以访问
		// 注意 当授权拦截后，shiro会自动跳转到未授权页面

		// 必须认证才可以访问
		filrerMap.put("/**", "authc");

		shiroFilterFactoryBaen.setFilterChainDefinitionMap(filrerMap);
		logout.info("shiro过滤器加载完成");
		return shiroFilterFactoryBaen;
	}

	/**
	 * 创建DefaultWebSecurityManager 配置安全管理器
	 */
	@Bean(name = "securityManager")
	public DefaultWebSecurityManager getDefaultWebSecurityManager() {
		logout.info("shiro正在加载安全管理器...");
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		// 关联Realm
		securityManager.setRealm(getRealm());
		// 自定义缓存实现
		// securityManager.setCacheManager(ehCacheManager());
		logout.info("shiro安全管理器加载完成");
		return securityManager;

	}

	/**
	 * 创建Realm
	 */
	@Bean(name = "myRealm")
	public MyRealm getRealm() {
		return new MyRealm();

	}

	/**
	 * Shiro生命周期处理器
	 * 
	 * @return
	 */
	@Bean
	public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}

	/**
	 * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),
	 * 需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
	 * 配置以下两个bean(DefaultAdvisorAutoProxyCreator
	 * (可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
	 * 
	 * @return
	 */
	@Bean
	@DependsOn({ "lifecycleBeanPostProcessor" })
	public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
		advisorAutoProxyCreator.setProxyTargetClass(true);
		return advisorAutoProxyCreator;
	}

	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
			@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}

	/**
	 * 开启缓存 shiro-ehcache实现
	 * 
	 * @return
	 */
	/*
	 * @Bean(name = "ehCacheManager") public EhCacheManager ehCacheManager() {
	 * logout.info("正在加载shiro缓存配置..."); EhCacheManager ehCacheManager = new
	 * EhCacheManager();
	 * ehCacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
	 * logout.info("shiro缓存配置加载完成"); return ehCacheManager; }
	 */

	/**
	 * shiro 权限 perms，roles，ssl，rest，port才是属于AuthorizationFilter
	 * 而anon，authcBasic，auchc，user是AuthenticationFilter，
	 * 所以在shiro未授权跳转页页面只属于AuthorizationFilter， 而属于AuthenticationFilter的 只能自定义处理
	 * 
	 * @return SimpleMappingExceptionResolver
	 * @author King
	 * @date 2018-9-4
	 */
	// @Bean(name = "simpleMappingExceptionResolver")
	public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {
		SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();

		Properties mappings = new Properties();
		mappings.setProperty("DatabaseException", "noAuth");
		mappings.setProperty("UnauthorizedException", "noAuth"); // 捕捉权限异常跳转403页面
		r.setExceptionMappings(mappings); // None by default
		r.setDefaultErrorView("error"); // No default
		r.setExceptionAttribute("ex");
		return r;
	}

}
